package com.chatplus.application.controller.api;

import cn.dev33.satoken.annotation.SaIgnore;
import cn.dev33.satoken.secure.BCrypt;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.chatplus.application.common.enumeration.AccountErrorCode;
import com.chatplus.application.common.enumeration.UserStatusEnum;
import com.chatplus.application.common.logging.SouthernQuietLogger;
import com.chatplus.application.common.logging.SouthernQuietLoggerFactory;
import com.chatplus.application.domain.dto.AdminConfigDto;
import com.chatplus.application.domain.dto.UserCustomChatConfigDto;
import com.chatplus.application.domain.entity.account.InviteCodeEntity;
import com.chatplus.application.domain.entity.account.UserEntity;
import com.chatplus.application.domain.request.AccountLoginRequest;
import com.chatplus.application.domain.request.AccountRegisterRequest;
import com.chatplus.application.domain.request.AccountUpdateRequest;
import com.chatplus.application.domain.response.AccountLoginResponse;
import com.chatplus.application.domain.response.AccountProfileResponse;
import com.chatplus.application.service.account.InviteCodeService;
import com.chatplus.application.service.account.UserService;
import com.chatplus.application.service.auth.authentication.UserAuthenticationService;
import com.chatplus.application.service.auth.request.AccountAuthenticationRequest;
import com.chatplus.application.service.basedata.ConfigService;
import com.chatplus.application.web.basecontroller.BaseController;
import com.chatplus.application.web.util.IpUtil;
import com.chatplus.application.web.verification.PlusCaptchaService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import java.util.List;
import java.util.Objects;

import static cn.hutool.core.lang.Assert.isTrue;

/**
 * 用户相关API
 */
@Validated
@RestController
@RequestMapping("/api/user")
@Tag(name = "用户信息API", description = "用户信息API")
public class AccountApiController extends BaseController {
    static final SouthernQuietLogger LOGGER = SouthernQuietLoggerFactory.getLogger(AccountApiController.class);
    private final UserAuthenticationService userAuthenticationService;
    private final UserService usersService;
    private final PlusCaptchaService smsCaptchaService;
    private final ConfigService configService;
    private final InviteCodeService inviteCodeService;

    @Autowired
    public AccountApiController(UserAuthenticationService userAuthenticationService, UserService usersService, ConfigService configService, InviteCodeService inviteCodeService, PlusCaptchaService smsCaptchaService) {
        this.userAuthenticationService = userAuthenticationService;
        this.usersService = usersService;
        this.smsCaptchaService = smsCaptchaService;
        this.configService = configService;
        this.inviteCodeService = inviteCodeService;
    }

    /**
     * 登录
     */
    @PostMapping("/login")
    @Operation(summary = "用户登录")
    @SaIgnore
    public String login(@RequestBody @Valid AccountLoginRequest accountLoginRequest, HttpServletRequest request) {
        LOGGER.message("用户发起登录请求").context("AccountRegisterRequest", accountLoginRequest).info();
        isTrue(usersService.getByUsername(accountLoginRequest.getUsername()) != null, AccountErrorCode.ACCOUNT_NOT_EXIST);
        AccountAuthenticationRequest accountAuthenticationRequest = new AccountAuthenticationRequest();
        BeanUtils.copyProperties(accountLoginRequest, accountAuthenticationRequest);
        accountAuthenticationRequest.setPhone(accountLoginRequest.getUsername());
        accountAuthenticationRequest.setRemoteIp(IpUtil.getRemoteIp(request));
        return userAuthenticationService.authenticate(accountAuthenticationRequest).getAuthorizationToken();
    }

    @PostMapping("/register")
    @SaIgnore
    @Operation(summary = "用户注册")
    public String register(@RequestBody @Valid AccountRegisterRequest accountRegisterRequest, HttpServletRequest request) {
        LOGGER.message("用户发起注册请求").context("AccountRegisterRequest", accountRegisterRequest).info();
        isTrue(accountRegisterRequest.getPassword().length() >= 8 && accountRegisterRequest.getPassword().length() <= 16, AccountErrorCode.NEW_PASSWORD_INVALID);
        isTrue(Objects.equals(accountRegisterRequest.getPassword(), accountRegisterRequest.getRepass()), AccountErrorCode.NEW_PASSWORD_AND_CONFIRM_PASSWORD_NOT_EQUAL);
        isTrue(usersService.getByUsername(accountRegisterRequest.getUsername()) == null, AccountErrorCode.PHONE_NUMBER_USED_BY_ANOTHER);
        boolean check = smsCaptchaService.checkCaptcha(accountRegisterRequest.getUsername(), accountRegisterRequest.getCode());
        // 校验入参
        isTrue(check, AccountErrorCode.CAPTCHA_IS_INVALID);
        // 保存用户
        AdminConfigDto adminConfigDto = configService.getSystemConfig();
        UserEntity accountEntity = BeanUtil.copyProperties(accountRegisterRequest, UserEntity.class, "password");
        if (adminConfigDto != null) {
            accountEntity.setCalls(adminConfigDto.getInitCalls());
            accountEntity.setImgCalls(adminConfigDto.getInitImgCalls());
            accountEntity.setChatModels(adminConfigDto.getDefaultModels());
            if (adminConfigDto.isForceInvite()) {
                isTrue(StringUtils.isNotEmpty(accountRegisterRequest.getInviteCode()), AccountErrorCode.FORCE_INVITE);
                InviteCodeEntity inviteCodeEntity = inviteCodeService.getByCode(accountRegisterRequest.getInviteCode());
                isTrue(inviteCodeEntity != null, AccountErrorCode.INVALID_INVITE_CODE);
                // TODO 对邀请的用户进行奖励
            }
        }
        accountEntity.setPassword(BCrypt.hashpw(accountRegisterRequest.getPassword()));
        // 设置其他必填信息,初始化用户的其他信息
        accountEntity.setAvatar("/images/avatar/user.png");
        accountEntity.setStatus(UserStatusEnum.OK);
        accountEntity.setChatRoles(List.of("gpt"));
        accountEntity.setChatConfig(new UserCustomChatConfigDto());
        accountEntity.setVip(Boolean.FALSE);
        usersService.save(accountEntity);
        // 登录操作
        AccountAuthenticationRequest accountAuthenticationRequest = new AccountAuthenticationRequest();
        accountAuthenticationRequest.setPhone(accountRegisterRequest.getUsername());
        accountAuthenticationRequest.setPassword(accountRegisterRequest.getPassword());
        accountAuthenticationRequest.setRemoteIp(IpUtil.getRemoteIp(request));
        return userAuthenticationService.authenticate(accountAuthenticationRequest).getAuthorizationToken();
    }

    @GetMapping("/session")
    @Operation(summary = "获取用户会话")
    public AccountLoginResponse session() {
        UserEntity userEntity = usersService.getById(getUserId());
        return BeanUtil.copyProperties(userEntity, AccountLoginResponse.class);
    }

    @GetMapping("/profile")
    @Operation(summary = "获取用户信息")
    public AccountProfileResponse profile() {
        UserEntity userEntity = usersService.getById(getUserId());
        return BeanUtil.copyProperties(userEntity, AccountProfileResponse.class);
    }
    @PostMapping("/profile/update")
    @Operation(summary = "修改用户信息")
    public void updateProfile(@RequestBody AccountUpdateRequest accountUpdateRequest) {
        UserEntity accountEntity = usersService.getById(getUserId());
        isTrue(accountEntity != null, AccountErrorCode.ACCOUNT_NOT_EXIST);
        accountEntity.setNickname(accountUpdateRequest.getNickname());
        usersService.updateById(accountEntity);
    }

    @PostMapping("/bind/username")
    @Operation(summary = "修改绑定账户")
    public void bindUsername(@RequestBody AccountUpdateRequest accountUpdateRequest) {
        boolean check = smsCaptchaService.checkCaptcha(accountUpdateRequest.getUsername(), accountUpdateRequest.getCode());
        // 校验入参
        isTrue(check, AccountErrorCode.CAPTCHA_IS_INVALID);
        UserEntity accountEntity = usersService.getById(getUserId());
        isTrue(accountEntity != null, AccountErrorCode.ACCOUNT_NOT_EXIST);
        assert accountEntity != null;
        accountEntity.setUsername(accountUpdateRequest.getUsername());
        usersService.updateById(accountEntity);
    }
    @PostMapping("/resetPass")
    @SaIgnore
    @Operation(summary = "重置密码")
    public void resetPass(@RequestBody AccountRegisterRequest resetPassRequest) {
        isTrue(resetPassRequest.getPassword().length() >= 8 && resetPassRequest.getPassword().length() <= 16, AccountErrorCode.NEW_PASSWORD_INVALID);
        isTrue(Objects.equals(resetPassRequest.getPassword(), resetPassRequest.getRepass()), AccountErrorCode.NEW_PASSWORD_AND_CONFIRM_PASSWORD_NOT_EQUAL);
        boolean check = smsCaptchaService.checkCaptcha(resetPassRequest.getUsername(), resetPassRequest.getCode());
        // 校验入参
        isTrue(check, AccountErrorCode.CAPTCHA_IS_INVALID);
        UserEntity accountEntity = usersService.getByUsername(resetPassRequest.getUsername());
        isTrue(accountEntity != null, AccountErrorCode.ACCOUNT_NOT_EXIST);

        LambdaUpdateWrapper<UserEntity> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(UserEntity::getId, getUserId());
        updateWrapper.set(UserEntity::getPassword, BCrypt.hashpw(resetPassRequest.getPassword()));
        usersService.update(updateWrapper);
    }
    @PostMapping("/password")
    @Operation(summary = "修改密码")
    public void password(@RequestBody AccountRegisterRequest resetPassRequest) {
        UserEntity accountEntity = usersService.getById(getUserId());
        isTrue(accountEntity != null, AccountErrorCode.ACCOUNT_NOT_EXIST);
        assert accountEntity != null;
        isTrue(BCrypt.checkpw(resetPassRequest.getOldPass(), accountEntity.getPassword()), AccountErrorCode.OLD_PASSWORD_INVALID);
        isTrue(resetPassRequest.getPassword().length() >= 8 && resetPassRequest.getPassword().length() <= 16, AccountErrorCode.NEW_PASSWORD_INVALID);
        isTrue(resetPassRequest.getPassword().equals(resetPassRequest.getRepass()), AccountErrorCode.NEW_PASSWORD_AND_CONFIRM_PASSWORD_NOT_EQUAL);
        LambdaUpdateWrapper<UserEntity> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(UserEntity::getId, getUserId());
        updateWrapper.set(UserEntity::getPassword, BCrypt.hashpw(resetPassRequest.getPassword()));
        usersService.update(updateWrapper);
    }
    /**
     * 退出当前登录的账号
     */
    @GetMapping("/logout")
    @Operation(summary = "用户退出登录")
    public void logout() {
        StpUtil.logout();
    }

}
